#include "qrreader.h"

using namespace std;

qrReader::qrReader()
{

}

void qrReader::readQrCode(QImage* img)
{
    for (int i = 0; i < 5; i++)
        seed[i] = 18+4*i;
    for (int i = 0; i < 7; i++)
    {
        seed2[i][0] = 6;
        seed2[i][1] = 22+2*i;
        seed2[i][2] = 38+4*i;
    }

    findCenters(img);
    if (angle != 0)
    {
        cout << "\nANGULO AJUSTADO";
        adjustImage(img);
        findCenters(img);
    }

    pixelProportion = determinePixelProportion(img);
    if (pixelProportion > 0)
    {        
        for (int row = 0; row < 8*pixelProportion; row += pixelProportion)
        {
            for (int col = 0; col < 8*pixelProportion; col += pixelProportion)
            {
                paintPixel(upperLeftCenter.getRow()-3*pixelProportion+row, upperLeftCenter.getCollumn()-3*pixelProportion+col, qRgb(0,255,0), img);
                paintPixel(upperRightCenter.getRow()-3*pixelProportion+row, upperRightCenter.getCollumn()-4*pixelProportion+col, qRgb(0,255,0), img);
                paintPixel(lowerLeftCenter.getRow()-4*pixelProportion+row, lowerLeftCenter.getCollumn()-3*pixelProportion+col, qRgb(0,255,0), img);
            }
        }
        origin.addCenter(upperLeftCenter.getRow()-3*pixelProportion, upperLeftCenter.getCollumn()-3*pixelProportion);
        versionINFO = checkVersion(upperLeftCenter, upperRightCenter, lowerLeftCenter, img);
        if (versionINFO > 0)
        {
            findTimming(upperLeftCenter, upperRightCenter, lowerLeftCenter, img);
            findFormat(upperLeftCenter, lowerLeftCenter, upperRightCenter, img);
            if (versionINFO > 1)
                findAlignments(upperLeftCenter, img);            
            if (maskPatern >= 0)
            {                
                cout << "\nTAMANHO EQUIVALENTE DO PIXEL = " << pixelProportion;
                cout << "\nVERSAO = " << versionINFO;
                cout << "\nECC LEVEL = " << eccLevel;
                cout << "\nMASCARA = " << maskPatern;
                dataBlocks = getDataBlocks(lowerLeftCenter, img);
                cout << "\nNUMERO DE BYTES = " << dataBlocks.size();
                //for (int i = 0; i < dataBlocks.size(); i++)
                    //cout << "\nBLOCO " << i+1 << " = " << dataBlocks.at(i);
                String data = decodeDataBlocks();
                if (data.size() != 0)
                {                             
                    cout << "\nDATA = " << data;
                    cout << "\n==================================\n";
                }                
            }            
        }
    }
}

void qrReader::findCenters(QImage* img)
{
    vector<center> centerList = checkHorizontalUpLeft(0, img->height()-1, img);
    upperLeftCenter = selectBestCenter(centerList);

    centerList = checkHorizontalDownLeft(img->height()-1, 0, img);
    lowerLeftCenter = selectBestCenter(centerList);

    centerList = checkHorizontalUpRight(0, img->height()-1, img);
    upperRightCenter = selectBestCenter(centerList);

    calculateAngle();
}

void qrReader::calculateAngle()
{
    int y = upperLeftCenter.getRow()-upperRightCenter.getRow();
    //cout << "\ny = " << y;
    int x = upperLeftCenter.getCollumn()-upperRightCenter.getCollumn();
    //cout << "\nx = " << x;
    if (x != 0)
    {
        angle = atan(abs(y)/abs(x));
        if (angle != 0)
            angle *= (x > 0)? 1 : -1;
    }
}

void qrReader::adjustImage(QImage *img)
{
    QTransform rotationAdjust;
    rotationAdjust.rotate(angle);

    *img = img->transformed(rotationAdjust);
}

center qrReader::selectBestCenter(vector<center> centerList)
{
    center cf;
    if (centerList.size() == 0)
        return cf;
    int total = 0;
    for (int i = 0; i < centerList.size(); i++)
    {
        center cAux = centerList.at(i);
        total += cAux.getRow();
    }
    int average = total/centerList.size();
    center c = centerList.at(0);
    cf.addCenter(average,c.getCollumn());
    return cf;
}

vector<center> qrReader::checkHorizontalUpLeft(int rowStart, int rowEnd, QImage *img)
{
    vector<center> centerList;

    int stateCount[5] = {0};
    int currentState = 0;
    bool found = false;
    bool over = false;
    int offset;

    for(int row = rowStart; row < rowEnd; row++)
    {
        if (over)
            break;

        stateCount[0] = 0;
        stateCount[1] = 0;
        stateCount[2] = 0;
        stateCount[3] = 0;
        stateCount[4] = 0;
        currentState = 0;

        offset = 0;

        for (int col = 0; col < img->width(); col++)
        {
            if(isPixelBlack(row, col, img))
            {
                if((currentState & 0x1)==1)
                    currentState++;
                stateCount[currentState]++;
            }
            else
            {
                if((currentState & 0x1)==1)
                    stateCount[currentState]++;
                else
                {
                    if(currentState==4)
                    {
                        if(checkRatio(stateCount))
                        {
                            int total = 0;
                            for (int i = 0; i < 5; i++)
                                total += stateCount[i];
                            if (crossCheckVertical(row - total/2, col - total/2, img))
                            {
                                int middle = (2*col-total)/2;
                                center c;
                                c.addCenter(row, middle);
                                centerList.push_back(c);
                                found = true;
                                //paintPixel(row, middle, qRgb(0,255,0), img);
                                break;
                            }
                        }
                        else
                        {
                            currentState  = 3;
                            stateCount[0] = stateCount[2];
                            stateCount[1] = stateCount[3];
                            stateCount[2] = stateCount[4];
                            stateCount[3] = 1;
                            stateCount[4] = 0;

                            offset++;
                            if (found & (offset > 1))
                            {
                                over = true;
                                break;
                            }
                            continue;
                        }
                        currentState  = 0;
                        stateCount[0] = 0;
                        stateCount[1] = 0;
                        stateCount[2] = 0;
                        stateCount[3] = 0;
                        stateCount[4] = 0;
                    }
                    else
                    {
                        currentState++;
                        stateCount[currentState]++;
                    }
                }
            }
        }
    }

    return centerList;
}

vector<center> qrReader::checkHorizontalDownLeft(int rowStart, int rowEnd, QImage *img)
{
    vector<center> centerList;

    int stateCount[5] = {0};
    int currentState = 0;
    bool found = false;
    bool over = false;
    int offset;

    for(int row = rowStart; row > rowEnd; row--)
    {
        if (over)
            break;

        stateCount[0] = 0;
        stateCount[1] = 0;
        stateCount[2] = 0;
        stateCount[3] = 0;
        stateCount[4] = 0;
        currentState = 0;

        offset = 0;

        for (int col = 0; col < img->width(); col++)
        {
            if(isPixelBlack(row, col, img))
            {
                if((currentState & 0x1)==1)
                    currentState++;
                stateCount[currentState]++;
            }
            else
            {
                if((currentState & 0x1)==1)
                    stateCount[currentState]++;
                else
                {
                    if(currentState==4)
                    {
                        if(checkRatio(stateCount))
                        {
                            int total = 0;
                            for (int i = 0; i < 5; i++)
                                total += stateCount[i];
                            if (crossCheckVertical(row - total/2, col - total/2, img))
                            {
                                int middle = (2*col-total)/2;
                                center c;
                                c.addCenter(row, middle);
                                centerList.push_back(c);
                                found = true;
                                //paintPixel(row, middle, qRgb(0,255,0), img);
                                break;
                            }
                        }
                        else
                        {
                            currentState  = 3;
                            stateCount[0] = stateCount[2];
                            stateCount[1] = stateCount[3];
                            stateCount[2] = stateCount[4];
                            stateCount[3] = 1;
                            stateCount[4] = 0;

                            offset++;
                            if (found & (offset > 1))
                            {
                                over = true;
                                break;
                            }
                            continue;
                        }
                        currentState  = 0;
                        stateCount[0] = 0;
                        stateCount[1] = 0;
                        stateCount[2] = 0;
                        stateCount[3] = 0;
                        stateCount[4] = 0;
                    }
                    else
                    {
                        currentState++;
                        stateCount[currentState]++;
                    }
                }
            }
        }
    }

    return centerList;
}

vector<center> qrReader::checkHorizontalUpRight(int rowStart, int rowEnd, QImage *img)
{
    vector<center> centerList;

    int stateCount[5] = {0};
    int currentState = 0;
    bool found = false;
    bool over = false;
    int offset;

    for(int row = rowStart; row < rowEnd; row++)
    {
        if (over)
            break;

        stateCount[0] = 0;
        stateCount[1] = 0;
        stateCount[2] = 0;
        stateCount[3] = 0;
        stateCount[4] = 0;
        currentState = 0;

        offset = 0;

        for (int col = img->width()-1; col > 0; col--)
        {
            if(isPixelBlack(row, col, img))
            {
                if((currentState & 0x1)==1)
                    currentState++;
                stateCount[currentState]++;
            }
            else
            {
                if((currentState & 0x1)==1)
                    stateCount[currentState]++;
                else
                {
                    if(currentState==4)
                    {
                        if(checkRatio(stateCount))
                        {
                            int total = 0;
                            for (int i = 0; i < 5; i++)
                                total += stateCount[i];
                            if (crossCheckVertical(row - total/2, col + total/2, img))
                            {
                                int middle = (2*col+total)/2;
                                center c;
                                c.addCenter(row, middle+1);
                                centerList.push_back(c);
                                found = true;
                                //paintPixel(row, middle+1, qRgb(0,255,0), img);
                                break;
                            }
                        }
                        else
                        {
                            currentState  = 3;
                            stateCount[0] = stateCount[2];
                            stateCount[1] = stateCount[3];
                            stateCount[2] = stateCount[4];
                            stateCount[3] = 1;
                            stateCount[4] = 0;

                            offset++;
                            if (found & (offset > 1))
                            {
                                over = true;
                                break;
                            }
                            continue;
                        }
                        currentState  = 0;
                        stateCount[0] = 0;
                        stateCount[1] = 0;
                        stateCount[2] = 0;
                        stateCount[3] = 0;
                        stateCount[4] = 0;
                    }
                    else
                    {
                        currentState++;
                        stateCount[currentState]++;
                    }
                }
            }
        }
    }

    return centerList;
}

bool qrReader::crossCheckVertical(int startRow, int startCol, QImage* img)
{
    int currentState = 0;
    int stateCount[5] = {0};
    for (int row = 0; row <= startCol*2; row++)
    {
        if (row + startRow > img->height()-1 || row + startRow < 0) {
            return false;
        }

        if(isPixelBlack(row + startRow, startCol, img))
        {
            if((currentState & 0x1)==1)
                currentState++;
            stateCount[currentState]++;
        }
        else
        {
            if((currentState & 0x1)==1)
                stateCount[currentState]++;
            else
            {
                if(currentState==4)
                {
                    if(checkRatio(stateCount))
                        return true;
                }
                else
                {
                    currentState++;
                    stateCount[currentState]++;
                }
            }
        }
    }
    return false;
}

bool qrReader::checkRatio(int stateCount[])
{
    int totalFinderSize = 0;
    for(int i=0; i<5; i++)
    {
        int count = stateCount[i];
        totalFinderSize += count;
        if(count==0)
            return false;
    }
    if(totalFinderSize<7)
        return false;
    // Calculate the size of one module
    int moduleSize = ceil(totalFinderSize / 7.0);
    int maxVariance = moduleSize/2;
    bool retVal= ((abs(moduleSize - (stateCount[0])) < maxVariance) &&
        (abs(moduleSize - (stateCount[1])) < maxVariance) &&
        (abs(3*moduleSize - (stateCount[2])) < 3*maxVariance) &&
        (abs(moduleSize - (stateCount[3])) < maxVariance) &&
        (abs(moduleSize - (stateCount[4])) < maxVariance));
    return retVal;
}

int qrReader::determinePixelProportion(QImage* img)
{
    int distance = abs(upperLeftCenter.getRow()-lowerLeftCenter.getRow());
    int proportion = distance;
    int propAux = 0;
    int middle = upperLeftCenter.getCollumn();
    for (int row = upperLeftCenter.getRow(); row < lowerLeftCenter.getRow(); row++)
    {
        if (isPixelBlack(row, middle, img))
            propAux++;
        else
        {
            if (proportion > propAux && propAux != 0)
                proportion = propAux;
            propAux = 0;
        }
    }

    return proportion;
}

int qrReader::checkVersion(center c1, center c2, center c3, QImage* img)
{
    int dimension = abs(c2.getCollumn()/pixelProportion-c1.getCollumn()/pixelProportion)+6;
    int version = (dimension-14)/4;
    if (version > 6)
        version = checkExactVersion(c2,c3,img);
    return version;
}

int qrReader::checkExactVersion(center c1, center c2, QImage* img)
{
    int version = 0;
    int counter = 17;

    for (int row = 0; row < 6*pixelProportion; row += pixelProportion)
    {
        for (int col = 0; col < 3*pixelProportion; col += pixelProportion)
        {
            if (isPixelBlack(c1.getRow()-(3*pixelProportion)+row,c1.getCollumn()-(7*pixelProportion)+col,img))
                version += 1 << counter;
            counter--;
            paintPixel(c1.getRow()-(3*pixelProportion)+row, c1.getCollumn()-(7*pixelProportion)+col, qRgb(32,255,200), img);
        }
    }

    int version2 = 0;
    counter = 17;

    for (int col = 0; col < 6*pixelProportion; col += pixelProportion)
    {
        for (int row = 0; row < 3*pixelProportion; row += pixelProportion)
        {
            if (isPixelBlack(c2.getRow()-(7*pixelProportion)+row, c2.getCollumn()-(3*pixelProportion)+col, img))
                version2 += 1 << counter;
            counter--;
            paintPixel(c2.getRow()-(7*pixelProportion)+row, c2.getCollumn()-(3*pixelProportion)+col, qRgb(32,255,200), img);
        }
    }

    if (version != version2)
        version = 0;

    switch (version) {
        case VERSION_7:
            return 7;
            break;
        case VERSION_8:
            return 8;
            break;
        case VERSION_9:
            return 9;
            break;
        case VERSION_10:
            return 10;
            break;
        case VERSION_11:
            return 11;
            break;
        case VERSION_12:
            return 12;
            break;
        case VERSION_13:
            return 13;
            break;
    }
}

void qrReader::findTimming (center c1, center c2, center c3, QImage* img)
{
    int dimension = abs(c2.getCollumn()-c1.getCollumn());
    int rowTimming = c1.getRow()+3*pixelProportion;
    for (int col = origin.getCollumn(); col < dimension+origin.getCollumn(); col += pixelProportion)
    {
        if (!isPattern(rowTimming, col, img))
            paintPixel(rowTimming, col, qRgb(232,229,63), img);
    }

    dimension = abs(c3.getRow()-c1.getRow());
    int colTimming = c1.getCollumn()+3*pixelProportion;
    for (int row = origin.getRow(); row < dimension+origin.getRow(); row += pixelProportion)
    {
        if (!isPattern(row, colTimming, img))
            paintPixel(row, colTimming, qRgb(232,229,63), img);
    }

    paintPixel(c3.getRow()-4*pixelProportion, c3.getCollumn()+5*pixelProportion, qRgb(232,229,63), img);
}

void qrReader::findFormat(center c1, center c2, center c3, QImage *img)
{
    int format = 0;
    int counter = 14;

    for (int col = 0; col < 8*pixelProportion; col += pixelProportion)
    {
        if (col != 6*pixelProportion)
        {
            if (isPixelBlack(c1.getRow()+(5*pixelProportion),c1.getCollumn()-(3*pixelProportion)+col, img))
                format += 1 << counter;
            counter--;
            paintPixel(c1.getRow()+(5*pixelProportion), c1.getCollumn()-(3*pixelProportion)+col, qRgb(0,0,255), img);
        }
    }

    for (int row = 0; row < 9*pixelProportion; row += pixelProportion)
    {
        if (row != 2*pixelProportion)
        {
            if (isPixelBlack(c1.getRow()+(5*pixelProportion)-row, c1.getCollumn()+(5*pixelProportion), img))
                format += 1 << counter;
            counter--;
            paintPixel(c1.getRow()+(5*pixelProportion)-row, c1.getCollumn()+(5*pixelProportion), qRgb(0,0,255), img);
        }
    }

    int format2 = 0;
    counter = 14;

    for (int row = 0; row < 7*pixelProportion; row += pixelProportion)
    {
        if (isPixelBlack(c2.getRow()+(3*pixelProportion)-row,c2.getCollumn()+(5*pixelProportion), img))
            format2 += 1 << counter;
        counter--;
        paintPixel(c2.getRow()+(3*pixelProportion)-row, c2.getCollumn()+(5*pixelProportion), qRgb(0,0,255), img);
    }

    for (int col = 0; col < 8*pixelProportion; col += pixelProportion)
    {
        if (isPixelBlack(c3.getRow()+(5*pixelProportion),c3.getCollumn()-(4*pixelProportion)+col,img))
            format2 += 1 << counter;
        counter--;
        paintPixel(c3.getRow()+(5*pixelProportion), c3.getCollumn()-(4*pixelProportion)+col, qRgb(0,0,255), img);
    }

    if (format != format2)
        format = 0;

    eccLevel = 'E';
    maskPatern = -1;
    switch (format) {
        case L_0:
            maskPatern = 0;
            eccLevel = 'L';
            break;
        case L_1:
            maskPatern = 1;
            eccLevel = 'L';
            break;
        case L_2:
            maskPatern = 2;
            eccLevel = 'L';
            break;
        case L_3:
            maskPatern = 3;
            eccLevel = 'L';
            break;
        case L_4:
            maskPatern = 4;
            eccLevel = 'L';
            break;
        case L_5:
            maskPatern = 5;
            eccLevel = 'L';
            break;
        case L_6:
            maskPatern = 6;
            eccLevel = 'L';
            break;
        case L_7:            
            maskPatern = 7;            
            eccLevel = 'L';
            break;
        case M_0:
            maskPatern = 0;
            eccLevel = 'M';
            break;
        case M_1:
            maskPatern = 1;
            eccLevel = 'M';
            break;
        case M_2:
            maskPatern = 2;
            eccLevel = 'M';
            break;
        case M_3:
            maskPatern = 3;
            eccLevel = 'M';
            break;
        case M_4:
            maskPatern = 4;
            eccLevel = 'M';
            break;
        case M_5:
            maskPatern = 5;
            eccLevel = 'M';
            break;
        case M_6:
            maskPatern = 6;
            eccLevel = 'M';
            break;
        case M_7:
            maskPatern = 7;
            eccLevel = 'M';
            break;
        case Q_0:
            maskPatern = 0;
            eccLevel = 'Q';
            break;
        case Q_1:
            maskPatern = 1;
            eccLevel = 'Q';
            break;
        case Q_2:
            maskPatern = 2;
            eccLevel = 'Q';
            break;
        case Q_3:
            maskPatern = 3;
            eccLevel = 'Q';
            break;
        case Q_4:
            maskPatern = 4;
            eccLevel = 'Q';
            break;
        case Q_5:
            maskPatern = 5;
            eccLevel = 'Q';
            break;
        case Q_6:
            maskPatern = 6;
            eccLevel = 'Q';
            break;
        case Q_7:
            maskPatern = 7;
            eccLevel = 'Q';
            break;
        case H_0:
            maskPatern = 0;
            eccLevel = 'H';
            break;
        case H_1:
            maskPatern = 1;
            eccLevel = 'H';
            break;
        case H_2:
            maskPatern = 2;
            eccLevel = 'H';
            break;
        case H_3:
            maskPatern = 3;
            eccLevel = 'H';
            break;
        case H_4:
            maskPatern = 4;
            eccLevel = 'H';
            break;
        case H_5:
            maskPatern = 5;
            eccLevel = 'H';
            break;
        case H_6:
            maskPatern = 6;
            eccLevel = 'H';
            break;
        case H_7:
            maskPatern = 7;
            eccLevel = 'H';
            break;
    }
}

void qrReader::findAlignments(center c, QImage *img)
{
    for (int row = 0; row < 5*pixelProportion; row += pixelProportion)
    {
        for (int col = 0; col < 5*pixelProportion; col += pixelProportion)
        {
            if (versionINFO < 7)
                paintPixel(seed[versionINFO-2]*pixelProportion+origin.getRow()-2*pixelProportion+row, seed[versionINFO-2]*pixelProportion+origin.getCollumn()-2*pixelProportion+col, qRgb(255,0,0), img);
            else
            {
                paintPixel(seed2[versionINFO-7][0]*pixelProportion+origin.getRow()-2*pixelProportion+row, seed2[versionINFO-7][1]*pixelProportion+origin.getCollumn()-2*pixelProportion+col, qRgb(255,0,0), img);
                paintPixel(seed2[versionINFO-7][1]*pixelProportion+origin.getRow()-2*pixelProportion+row, seed2[versionINFO-7][0]*pixelProportion+origin.getCollumn()-2*pixelProportion+col, qRgb(255,0,0), img);
                paintPixel(seed2[versionINFO-7][1]*pixelProportion+origin.getRow()-2*pixelProportion+row, seed2[versionINFO-7][1]*pixelProportion+origin.getCollumn()-2*pixelProportion+col, qRgb(255,0,0), img);
                paintPixel(seed2[versionINFO-7][1]*pixelProportion+origin.getRow()-2*pixelProportion+row, seed2[versionINFO-7][2]*pixelProportion+origin.getCollumn()-2*pixelProportion+col, qRgb(255,0,0), img);
                paintPixel(seed2[versionINFO-7][2]*pixelProportion+origin.getRow()-2*pixelProportion+row, seed2[versionINFO-7][1]*pixelProportion+origin.getCollumn()-2*pixelProportion+col, qRgb(255,0,0), img);
                paintPixel(seed2[versionINFO-7][2]*pixelProportion+origin.getRow()-2*pixelProportion+row, seed2[versionINFO-7][2]*pixelProportion+origin.getCollumn()-2*pixelProportion+col, qRgb(255,0,0), img);
            }
        }
    }
}

void qrReader::unMask(int x, int y, QImage *img)
{
    int xAux = (x-origin.getRow())/pixelProportion;
    int yAux = (y-origin.getCollumn())/pixelProportion;
    bool notReverse;
    switch (maskPatern) {
        case 0: // 000
            if ((xAux + yAux) % 2 == 0)
                reversePixel(x, y, img);
            else
                notReverse = true;
            break;
        case 1: // 001
            if (xAux % 2 == 0)
                reversePixel(x, y, img);
            else
                notReverse = true;
            break;
        case 2: // 010
            if (yAux % 3 == 0)
                reversePixel(x, y, img);
            else
                notReverse = true;
            break;
        case 3: // 011
            if ((xAux + yAux) % 3 == 0)
                reversePixel(x, y, img);
            else
                notReverse = true;
            break;
        case 4: // 100
            if ((xAux / 2 + yAux / 3) % 2 == 0)
                reversePixel(x, y, img);
            else
                notReverse = true;
            break;
        case 5: // 101
            if ((xAux * yAux) % 2 + (xAux * yAux) % 3 == 0)
                reversePixel(x, y, img);
            else
                notReverse = true;
            break;
        case 6: // 110
            if (((xAux * yAux) % 2 + (xAux * yAux) % 3) % 2 == 0)
                reversePixel(x, y, img);
            else
                notReverse = true;
            break;
        case 7: // 111
            if (((xAux * yAux) % 3 + (xAux + yAux) % 2) % 2 == 0)
                reversePixel(x, y, img);
            else
                notReverse = true;
            break;
        }
    if (notReverse)
    {
        if (isPixelBlack(x, y, img))
            paintPixel(x, y, qRgb(0,0,0), img);
        else
            paintPixel(x, y, qRgb(255,255,255), img);
    }
}

vector<int> qrReader::getDataBlocks(center c, QImage *img)
{
    vector<int> blocks;
    int word = 0;
    int blockCounter = 7;
    int lastCol = c.getCollumn()-3*pixelProportion;
    int lastRowUp = c.getRow()-13*pixelProportion-4*versionINFO*pixelProportion;
    int lastRowDown = c.getRow()+3*pixelProportion;
    int row = lastRowDown;
    int col = c.getCollumn()+13*pixelProportion+4*versionINFO*pixelProportion;

    while (col > lastCol)
    {
        if (row != lastRowUp)
        {
            while (row >= lastRowUp)
            {
                for (int i = 0; i <= pixelProportion; i += pixelProportion)
                {
                    if (!isPattern(row, col-i, img))
                    {
                        unMask(row, col-i, img);
                        if (isPixelBlack(row, col-i, img))
                            word += 1 << blockCounter;
                        blockCounter--;
                        if (blockCounter == -1)
                        {
                            blocks.push_back(word);
                            word = 0;
                            blockCounter = 7;
                        }
                        //paintPixel(row,col-i,img);
                    }
                }
                row -= pixelProportion;
            }
            row += pixelProportion;
        }
        else
        {
            while (row <= lastRowDown)
            {
                for (int i = 0; i <= pixelProportion; i += pixelProportion)
                {
                    if (!isPattern(row, col-i, img))
                    {
                        unMask(row, col-i, img);
                        if (isPixelBlack(row, col-i, img))
                            word += 1 << blockCounter;
                        blockCounter--;
                        if (blockCounter == -1)
                        {
                            blocks.push_back(word);
                            word = 0;
                            blockCounter = 7;
                        }
                        //paintPixel(row,col-i,img);
                    }
                }
                row += pixelProportion;
            }
            row -= pixelProportion;
        }
        col -= 2*pixelProportion;
    }

    return correctDataBlocks(blocks);
}

vector<int> qrReader::correctDataBlocks(vector<int> dataBlocks)
{
    return dataBlocks;
}

String qrReader::decodeDataBlocks()
{
    int mode;
    int sizeDataLenght;
    int numBlock = 0;
    String data = "";
    while (true)
    {
        mode = (dataBlocks[numBlock] & 240) >> 4;
        if (mode != 4)
            break;
        cout << "\nMODE = " << mode;
        sizeDataLenght = 0;
        if (versionINFO <= 9)
        {
            sizeDataLenght = (dataBlocks[numBlock] & 15) << 4;
            sizeDataLenght += (dataBlocks[numBlock+1]) >> 4;
            numBlock++;
        }
        else
        {
            sizeDataLenght = (dataBlocks[numBlock] & 15) << 12;
            sizeDataLenght += (dataBlocks[numBlock+1]) << 4;
            sizeDataLenght += (dataBlocks[numBlock+2] & 240) >> 4;
            numBlock += 2;
        }
        cout << "\nNUMERO DE CARACTERES = " << sizeDataLenght;

        switch (mode) {
            case NUMERIC_MODE:
                data = decodeNumeric(sizeDataLenght, &numBlock);
                break;
            case ALPHA_NUMERIC_MODE:
                data = decodeAlnum(sizeDataLenght, &numBlock);
                break;
            case BINARY_MODE:
                data = decodeBinary(sizeDataLenght, &numBlock);
                break;
            case JAPANESE_MODE:
                data = decodeJapanese(sizeDataLenght, &numBlock);
                break;
        }
    }
    return data;
}

String qrReader::decodeNumeric(int sizeDataLenght, int *numBlock)
{
    String data = "";
    return data;
}

String qrReader::decodeAlnum(int sizeDataLenght, int *numBlock)
{
    String data = "";
    return data;
}

String qrReader::decodeBinary(int sizeDataLenght, int *numBlock)
{
    int intData;
    String data = "";
    for (int i = 0; i < sizeDataLenght; i++)
    {
        intData = (dataBlocks[(*numBlock)] & 15) << 4;
        intData += (dataBlocks[(*numBlock)+1]) >> 4;
        (*numBlock)++;
        //cout << "\nintData = " << intData;
        data += (char) intData;
    }

    return data;
}

String qrReader::decodeJapanese(int sizeDataLenght, int *numBlock)
{
    String data = "";
    return data;
}

bool qrReader::isPixelBlack(int row, int col, QImage *img)
{
    if (col < 0 || col > img->width()-1 || row < 0 || row > img->height()-1)
        return false;
    return (qGray(img->pixel(QPoint(col,row))) < 128);
}

void qrReader::paintPixel(int row, int col, QRgb color, QImage *img)
{
    int x;
    if (pixelProportion > 1)
        x = pixelProportion-2;
    else
        x = 0;
    if (col-x > 0 & col+x < img->width()-x & row-x > 0 & row+x < img->height()-x)
    {
        if (x > 0)
        {
            for (int i = -x; i <= x; i++)
                for (int j = -x; j <= x; j++)
                    img->setPixel(QPoint(col+i, row+j), color);
        }
        else
            img->setPixel(QPoint(col, row), color);
    }
}

void qrReader::reversePixel(int row, int col, QImage *img)
{
    int x;
    if (pixelProportion > 1)
        x = pixelProportion-2;
    else
        x = 0;
    if (col-x > 0 & col+x < img->width()-x & row-x > 0 & row+x < img->height()-x)
    {
        if (qGray(img->pixel(QPoint(col,row))) < 128)
        {
            if (x > 0)
            {
                for (int i = -x; i <= x; i++)
                    for (int j = -x; j <= x; j++)
                        img->setPixel(QPoint(col+i, row+j), qRgb(255,255,255));
            }
            else
                img->setPixel(QPoint(col, row), qRgb(255,255,255));
        }
        else
        {
            if (x > 0)
            {
                for (int i = -x; i <= x; i++)
                    for (int j = -x; j <= x; j++)
                        img->setPixel(QPoint(col+i, row+j), qRgb(0,0,0));
            }
            else
                img->setPixel(QPoint(col, row), qRgb(0,0,0));
        }
    }
}

bool qrReader::isPattern(int row, int col, QImage *img)
{
    if (col < 0 || col > img->width()-1 || row < 0 || row > img->height()-1)
        return true;
    if ((img->pixel(QPoint(col,row)) == qRgb(0,255,0)))    //Finder pattern
        return true;
    if ((img->pixel(QPoint(col,row)) == qRgb(232,229,63))) //Timming pattern
        return true;
    if ((img->pixel(QPoint(col,row)) == qRgb(0,0,255)))    //Format pattern
        return true;
    if ((img->pixel(QPoint(col,row)) == qRgb(32,255,200))) //Version pattern
        return true;
    if ((img->pixel(QPoint(col,row)) == qRgb(255,0,0)))    //Alignment pattern
        return true;
    return false;
}
